package logic

import (
	"gameserver/entitydef"
	"gameserver/messages"
	"gameserver/server"
	"gameserver/server/Gateway/internal"
	"gameserver/server/redisutil"
	"time"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/dbmanager"
	"gitee.com/night-tc/gobige/entity"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/msgdef/protomsg"
	"gitee.com/night-tc/gobige/timerwheel"
)

var _ entity.IEntityReal = &Player{}

type Player struct {
	entity.Entity
	entitydef.NttPlayerByGatewayDef
	entity.DelayCallHost

	/* 定时器 */
	Timer *timerwheel.Timer

	/* 以下属性在server 协程使用 */
	// //是否第一次连接上来
	// isfirst   bool
	outtimeid uint64 //玩家掉线时的定时器ID，处理掉线后一段时间后才删内存数据
}

//////////////////////////////////////////////////////////////////////////////
/* 重载 */

func (this *Player) OnCreated(etype string, eid, dbid uint64, realPtr entity.IEntity, spacePtr entity.IEntities, fly bool, param ...interface{}) error {
	if err := this.Entity.OnCreated(etype, eid, dbid, realPtr, spacePtr, fly, param...); err != nil {
		return err
	}

	if err := this.Init(); err != nil {
		return err
	}
	return nil
}

// 初始化
func (this *Player) Init() error {
	this.RegMsgProc(&Player_Proc{this})
	// // 这是与客户端直连的服务器
	this.IsDirectMode.Store(true)
	if err := this.saveSession(); err != nil {
		return err
	}
	// this.isfirst = true
	if err := this.Entity.Init(); err != nil {
		return err
	}
	this.Timer = timerwheel.NewTimer()
	this.Timer.Start()
	return nil
}

// 循环调用中
func (this *Player) Looping() {
	this.Timer.OnTick(this.GetNowTime())
	this.Entity.Looping()
}

func (this *Player) Looped() {
	this.Exec()
	this.Entity.Looped()
}
func (this *Player) Destroy() {
	if sessmd := this.GetClientSess(); sessmd != nil {
		// 只能在这里发通知客户端被T的消息
		sessmd.SendNow(&protomsg.ReturnLoginNtf{})
	}
	this.Entity.Destroy()
	this.Timer.DeleteAllTimerTask()
}

/* 重载 */
//////////////////////////////////////////////////////////////////////////////
/* 自定义 */

// 玩家断线重连
func (this *Player) ReLoadPlayer(state uint32) {
	/*
	   先找一下所有与之连接的服务器,把重连的事件通知过去;
	   然后判断lobby服有没有,没有就找一个给他
	   判断db服有没有,没有就找一个给他
	*/
	srvli := this.GetSrvInfoAll()
	remsg := new(messages.ReLoadPlayerSrv)
	remsg.SessState = state
	for _, srvmd := range srvli {
		if srvmd.Stype != global.GetCfgInst().GetSrvType() {
			_ = global.GetSrvInst().PostMsgToEntity(srvmd.SrvID, srvmd.SpaceID, this.GetEntityID(), remsg)
		}
	}
	this.InitGameSess()
	this.InitDbServerSess()
}

// 生成玩家lobby服务器的对象
func (this *Player) InitGameSess(...interface{}) {
	if _, err := this.GetSrvByStype(server.ServerType_Game); err == nil {
		return
	}
	//没有lobby服,给他找一个
	sinfo, err := internal.GetSrvinst().GetDirMgr().GetServerByType(global.GetCfgInst().GetGroupID(),
		server.ServerType_Game)
	if err != nil {
		logger.Errorf("InitLobbySess pid:%d;nttid:%d err:%v", this.GetDBID(), this.GetEntityID(), err)
	} else if err := this.CreateEntityByStype(server.ServerType_Game, 0, sinfo.GetServerID(), this.callbackCreateGame); err != nil {
		logger.Errorf("InitLobbySess pid:%d;nttid:%d err:%v", this.GetDBID(), this.GetEntityID(), err)
	} else {
		// 发成功了
		return
	}
	// 没发成功就加个时间重来
	this.Timer.OnceTimer(time.Second*5, this.InitGameSess)
}

func (this *Player) callbackCreateGame(ret *protomsg.RouteMsgSrvRet, err error) {
	if err != nil {
		logger.Warnf("callbackCreateEntityByStype pid:%d;nttid:%d;err:%s", this.GetDBID(), this.GetEntityID(), err)
		this.InitGameSess()
	}
}

// 生成玩家的DB服务器的会话;
func (this *Player) InitDbServerSess() {
	_, err := dbmanager.GetDBServer(dbmanager.NewEntityUtilDBData(this.GetDBID()), this.GetEntityID())
	if err != nil {
		logger.Errorf("PlayerID:%d InitDbServerSess:%s", this.GetDBID(), err)
		return
	}
}

// 玩家登出服务器
func (this *Player) LogoutPlayer() {
	logger.Debugf(server.LogKey_LoginFlow, "LogoutPlayer pid:%d,nttid:%d", this.GetDBID(), this.GetEntityID())

	if this.Post(server.ServerType_Game, &messages.LogoutPlayerSrv{}) == nil {
		// Lobby服务器，让它处理退出逻辑
		return
	}
	/*
		需要把其他服务器上的用户对象都删了
	*/
	msg := new(protomsg.DestroyEntityReqSrv)
	msg.EntityID = this.GetEntityID()
	msg.SrcEntityID = this.GetEntityID()
	msg.SrcSpaceID = 0
	msg.SrcSrvID = global.GetCfgInst().GetServerID()
	msg.CallbackID = global.GetSrvInst().GetNewEID()

	// sinfo, err := this.GetSrvByStype(server.ServerType_Game)
	// if err != nil {
	// 	logger.Errorf("LogoutPlayer pid:%d,nttid:%d;err:%s", this.GetDBID(), this.GetEntityID(), err)
	// 	_ = this.GetEntities().DestroyEntity(this.GetEntityID())
	// 	return
	// }
	// global.PostSrvAsync(sinfo.SrvID, msg,
	// 	func(ret *protomsg.RouteMsgSrvRet, err error) {
	// 		if err != nil {
	// 			logger.Errorf("LogoutPlayer pid:%d,nttid:%d;err:%s", this.GetDBID(), this.GetEntityID(), err)
	// 		}
	// 		_ = this.GetEntities().DestroyEntity(this.GetEntityID())
	// 	},
	// 	global.SrvSetPID(this.GetDBID()),
	// 	global.SrvSetEID(sinfo.SpaceID, this.GetEntityID()),
	// )

	srvli := this.GetSrvInfoAll()
	for _, srvmd := range srvli {
		if srvmd.Stype == global.ServerTypeClient {
			// 客户端需要跳过
			continue
		}
		if srvmd.Stype != global.GetCfgInst().GetSrvType() {
			global.GetSrvInst().PostSess(srvmd.SrvID, msg)
		}
	}
	_ = this.GetEntities().DestroyEntity(this.GetEntityID())
}

// 保存玩家会话数据到redis
// 这里的会话数据是指玩家登录后，链接gateway服务器必要的数据
func (this *Player) saveSession() error {
	gsrd := redisutil.NewGateSession(this.GetDBID())
	reterr := gsrd.SaveInfo(nil, map[string]any{
		redisutil.GeteSession_Key_EntityID: common.NewStringAny(this.GetEntityID()).String(),
	})

	return reterr
}

//------------------------------------------------------------------------------
/* IMsgOwner */

// 处理消息前
func (this *Player) OnMsgBefore(name string, msg msgdef.IMsg) {
	if name == "HeartBeat" {
		return
	}
	logger.Debugf(logger.LogKey_Msg, "OnMsgBefore:%s;", name)
}

// // 处理消息后
// OnMsged(name string, msg msgdef.IMsg)
// 处理RPC消息前
func (this *Player) OnRpcBefore(name string, msg msgdef.IMsg) {
	logger.Debugf(logger.LogKey_Msg, "OnRpcBefore:%s;", name)

}

// // 处理RPC消息后
// OnRpced(name string, msg msgdef.IMsg)
